Agenda for June 22,2016:

-- Get the solution of the 8 following questions in class time:


Hint: Python list operation:
l String to list
l List to string
l List how to iterate

Reference
http://codingbat.com/doc/python-lists.html
https://docs.python.org/3/library/turtle.html
http://openbookproject.net/thinkcs/python/english3e/conditionals.html

1. Define a function sum() and a function multiply() that sums and multiplies (respectively) all the numbers in a list of numbers. For example, sum([1, 2, 3, 4]) should return 10, and multiply([1, 2, 3, 4]) should return 24.

2. Define a function reverse() that computes the reversal of a string. For example, reverse("I am testing") should return the string "gnitset ma I".

3. Define a function is_palindrome() that recognizes palindromes (i.e. words that look the same written backwards). For example, is_palindrome("radar") should return True.

4. Write a function is_member() that takes a value (i.e. a number, string, etc) x and a list of values a, and returns True if x is a member of a, False otherwise. (Note that this is exactly what the in operator does, but for the sake of the exercise you should pretend Python did not have this operator.)

5. Define a function overlapping() that takes two lists and returns True if they have at least one member in common, False otherwise. You may use your is_member() function, or the in operator, but for the sake of the exercise, you should (also) write it using two nested for-loops.

6. Define a function generate_n_chars() that takes an integer n and a character c and returns a string, n characters long, consisting only of c:s. For example, generate_n_chars(5,"x") should return the string "xxxxx". (Python is unusual in that you can actually write an expression 5 * "x" that will evaluate to "xxxxx". For the sake of the exercise you should ignore that the problem can be solved in this manner.)

7. Define a procedure histogram() that takes a list of integers and prints a histogram to the screen. For example,histogram([4, 9, 7]) should print the following:


*
***
8. Plot a pie graph for a list of numerical inputs, better with fill colors and labels.

Sample codes and optimized version(programmed by Tom Zhou and optimized by Mrs. Wudi):


If you have seen these codes and optimized versions, you will probably find that there is no difference between their functionality. However, optimizations do somehow make the codes more understandable and intuitive, or improve the algorithm and thus reduce the workload of computer.**

Q1:

def Sum(a):
    summ = 0
    for i in range(0,len(a)):
        summ += a[i]
    return summ
def multiply(a):
    resultt = 1
    for i in range(0, len(a)):
        resultt = resultt * a[i]
    return resultt
a = [1,2,3,4]
print (Sum(a),multiply(a))

Optimization:

# <>: to be replaced by specific variables
# for <loop variable> in <list>:
# for each loop <loop variable>  is going to take one element from <list> in the order of left to right.
# Q1: Opt Version
def Sum(a):
    summ = 0
    for i in a:   # for i in a:
        summ += i            #   summ += i
    return summ
def multiply(a):
    resultt = 1
    for i in a:   # the same as above
        resultt = resultt * i
    return resultt
 
a = [1,2,3,4]
print (Sum(a),multiply(a))

Q2:

def reverse(a):
    a = a[::-1]
    return a
a = "Roll out!"
print(reverse(a))

Optimization:

# using a[:,:,-1] is almost no difference to a.reverse....
# sample code below:
### Q2 : opt Version
def reverse(a):
    b = ''
    for i in a:
        b = i + b
    return b
InputStr = "Roll out!"
print(reverse(InputStr))

Q3:

def is_palindrome(a):
    if a[::-1] == a:
        return True
    else:
        return False
print(is_palindrome("dad"))

Optimization:

# Well, you can use the function you've defined above....
### Q3 : opt Version
def is_palindrome(a):
    if a == reverse(a):
        return True
    else:
        return False
print(is_palindrome("dad"))

Q4:

def is_member(a,list):
    for i in range(0,len(list)):
        if list[i] == a:
            tf = True
            break
        else:
            tf = False
    return tf
list = [1,2,3,4,5]
a = 4
print (is_member(a,list) )

Optimization:

# again: to visit every element of the list, no need to use index
# also you can use a boolean flag variable for return
# Also list is not suitable for a variable name!
### Q4 : opt Version
def is_member(x,a):
    flag = False
    for i in a:
        if x == i:
            flag = True
    return flag
 
a = [1,2,3,4,5]
x = 4
print (is_member(x,a) )

Q5:

def overlapping(list1,list2):
    for i1 in range(0,len(list1)):
        for i2 in range(0, len(list2)):
            if list1[i1] == list2[i2]:
                tf = True
                break
            else:
                tf = False
        if tf == True:
            break
    return tf
list1 = [5,6,7,8,9]
list2 = [3,4,5,1,2]
print (overlapping(list1,list2))

Optimization:

# guys, you can make full use of your own code!
## Q5 -- Opt Version
def is_member(x,a):
    flag = False
    for i in a:
        if x == i:
            flag = True
    return flag
def overlapping(list1,list2):
    flag = False
    for i1 in list1:
        if is_member(i1,list2):
            flag = True
    return flag
list1 = [5,6,7,8,9]
list2 = [3,4,5,1,2]
print (overlapping(list1,list2))

Q6:

def generate_n_chars(number,char):
    chars = char
    for i in range (0,number-1):
        chars += char
    return chars
number = 99
char = "6"
print(generate_n_chars(number,char))

Optimization:

# The following is a bit more intuitive?
## Q6 Opt Version
def generate_n_chars(number,char):
    chars = ''
    for i in range (number):
        chars += char
    return chars
number = 99
char = "6"
print(generate_n_chars(number,char))

Q7:

def histogram(list):
    for x in range(0,len(list)):
        bar = ""
        for y in range(0,list[x]):
            bar += "*"
        print(bar)
list = [5,7,2,4]
histogram(list)

Optimization:

# again, same list iteration problem
# use your own defined function
# reasonable variable name
### Q7 -- Opt Version
def generate_n_chars(number,char):
    chars = char
    for i in range (0,number-1):
        chars += char
    return chars
 
def histogram(lista,symbol):
    for x in lista:
        print(generate_n_chars(x,symbol))
 
Input_list = [5,7,2,4]
histogram(Input_list,'@')

Q8:

import turtle
import random
Window = turtle.Screen()
Tom = turtle.Turtle()
Tom.hideturtle()
Window.colormode(255)
Tom.speed(0)
def piegraph(list,radius,label):
    Tom.left(90)
    for i in range(0,len(list)):
        Tom.fillcolor(int(random.uniform(0,255)),int(random.uniform(0,255)),int(random.uniform(0,255)))
        Tom.begin_fill()
        Tom.forward(radius)
        Tom.right(90)
        Tom.circle(-radius,180 * (list[i]/sum(list)))
        xcor = Tom.xcor()
        ycor = Tom.ycor()
        Tom.left(90)
        angle  = Tom.heading()
        Tom.right(90)
        Tom.circle(-radius, 180 * (list[i] / sum(list)))
        Tom.right(90)
        Tom.forward(radius)
        Tom.end_fill()
        Tom.left(180)
        xcor1 = Tom.xcor()
        ycor1 = Tom.ycor()
        Tom.penup()
        Tom.goto(xcor,ycor)
        Tom.pendown()
        oldangle = Tom.heading()
        if angle <= 90 or angle >=270:
            Tom.setheading(angle)
            Tom.forward(40)
            Tom.penup()
            Tom.forward(20)
            Tom.write(label[i] + " " + str(round(list[i] / sum(list) * 100,1)) + "%",False,align = "left",font = ("Calibri",14,"bold"))
            Tom.goto(xcor1,ycor1)
            Tom.setheading(oldangle)
            Tom.pendown()
        else:
            Tom.setheading(angle)
            Tom.forward(40)
            Tom.penup()
            Tom.forward(10)
            Tom.write(label[i] + " " + str(round(list[i] / sum(list) * 100,1)) + "%", False, align="right", font=("Calibri", 14, "bold"))
            Tom.goto(xcor1, ycor1)
            Tom.setheading(oldangle)
            Tom.pendown()
list = []
label = []
radius = 0
while 1:
    appendix = input("Please enter your data, one at a time. Type 'stop' to stop.")
    if appendix == "stop":
        break
    list.append(int(appendix))
while 1:
    appendix = input("Please enter your label corresponding to your data, one at a time. Type 'stop' to stop.")
    if appendix == "stop":
        break
    label.append(appendix)
radius = int(input("Please enter the radius of the pie."))
piegraph(list,radius,label)
Window.mainloop()

Because I like to draw short lines pointing outward to label each segment and have a separated list of labels, so I optimized my own code. In addition, my version has the instructions for user interactions. Mrs. Wudi's optimized and more concise version was shown at the bottom.

Optimization by Tom:

import turtle
import random
Window = turtle.Screen()
Tom = turtle.Turtle()
Tom.hideturtle()
Window.colormode(255)
Tom.speed(0)
def piegraph(list1, radius, label):
    Tom.left(90)
    # pre-calculation of sum can avoid repetitive calculation inside the loop.
    list_sum = sum(list1)
    # because there're two bijective lists, one index can acquire members of both lists correctly.
    for i in range(0, len(list1)):
        Tom.fillcolor(int(random.uniform(0, 255)), int(random.uniform(0, 255)), int(random.uniform(0, 255)))
        Tom.begin_fill()
        Tom.forward(radius)
        Tom.right(90)
        Tom.circle(-radius, 180 * (list1[i]/list_sum))
        # draw a line outside and perpendicular to the arc
        Tom.left(90)
        Tom.forward(40)
        Tom.penup()
        Tom.forward(20)
        # adjust the position of text
        if 90 <= Tom.heading() <= 270:
            ali = "right"
        else:
            ali = "left"
        Tom.write(label[i] + ": " + str(round(list1[i] / list_sum * 100, 2)) + "%", False, align=ali, font=("Calibri", 14, "bold"))
        # go back to original position and continue drawing other half of the arc
        Tom.backward(60)
        Tom.right(90)
        Tom.pendown()
        Tom.circle(-radius, 180 * (list1[i] / list_sum))
        Tom.right(90)
        Tom.forward(radius)
        Tom.end_fill()
        Tom.left(180)
list1 = []
label = []
while 1:
    appendix = input("Please enter your data, one at a time. Type 'stop' to stop.")
    if appendix == "stop":
        break
    list1.append(int(appendix))
list1.sort(reverse=True)
while 1:
    appendix = input("Please enter your labels corresponding to your data, one at a time. Type 'stop' to stop.")
    if appendix == "stop":
        break
    label.append(appendix)
radius = int(input("Please enter the radius of the pie."))
piegraph(list1, radius, label)
Window.mainloop()

Optimization by Mrs. Wudi:

### A more concise version which combines the implementation of Doris' and Tom's
### Q8 -- Opt Version
import turtle
import random
Window = turtle.Screen()
Tom = turtle.Turtle()
Tom.hideturtle()
Window.colormode(255)  ### Use the R,G,B color ocmponent color mode is very good.
Tom.speed(10)
 
def pie_chart(list1,radius):
    list_sum = sum(list1)
    for i0 in list1:
        i = round(i0 / list_sum,2)
        Tom.fillcolor(int(random.uniform(0,255)),int(random.uniform(0,255)),int(random.uniform(0,255)))
        Tom.begin_fill()
        Tom.forward(radius)
        Tom.left(90)
        Tom.circle(radius,360*i)
        Tom.right(90)
        Tom.goto(0,0)
        Tom.end_fill()
 
        ### write labels
        Tom.penup()
        Tom.right(180*i)
        Tom.forward(radius + 30)
        labelText = str(i0) + ": " + str(i)
        Tom.write(labelText, True, align="center", font=("Calibri", 12, "bold"))
        Tom.goto(0,0)
        Tom.left(180*i)
        Tom.pendown()
 
    Window.mainloop()
 
pie_chart([30,20,40,50,15],200)